/*
REWRITTEN FROM SCRATCH BY XINEF, IT OWNS NOW!
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "vault_of_archavon.h"
#include "SpellAuras.h"
#include "PassiveAI.h"
#include "Player.h"

enum Spells
{
    // Toravon
    SPELL_FREEZING_GROUND				= 72090,
    SPELL_FROZEN_ORB					= 72091,
    SPELL_WHITEOUT						= 72034,
    SPELL_FROZEN_MALLET					= 71993,

    // Frozen Orb
    SPELL_FROZEN_ORB_DMG				= 72081,    // priodic dmg aura
    SPELL_FROZEN_ORB_AURA				= 72067,    // make visible

    // Frozen Orb Stalker
	SPELL_FROZEN_ORB_STALKER_VISUAL		= 72094,
};

enum Events
{
    EVENT_FREEZING_GROUND				= 1,
    EVENT_FROZEN_ORB_STALKER			= 2,
	EVENT_CHECK_SUMMONS					= 3,
};

enum Misc
{
	NPC_FROZEN_ORB						= 38456,
	NPC_FROZEN_ORB_STALKER				= 38461,
};


class boss_toravon : public CreatureScript
{
    public:
        boss_toravon() : CreatureScript("boss_toravon") { }

        struct boss_toravonAI : public ScriptedAI
        {
            boss_toravonAI(Creature* creature) : ScriptedAI(creature), summons(me)
            {
				pInstance = me->GetInstanceScript();
            }

			InstanceScript* pInstance;
			EventMap events;
			SummonList summons;

			void Reset()
			{
				events.Reset();
				summons.DespawnAll();
				if (pInstance)
				{
					if (pInstance->GetData(DATA_STONED))
					{
						if (Aura* aur = me->AddAura(SPELL_STONED_AURA, me))
						{
							aur->SetMaxDuration(60 * MINUTE* IN_MILLISECONDS);
							aur->SetDuration(60 * MINUTE* IN_MILLISECONDS);
						}
					}
					pInstance->SetData(EVENT_TORAVON, NOT_STARTED);
				}
			}

			void AttackStart(Unit* who)
			{
				if (me->HasAura(SPELL_STONED_AURA))
					return;

				ScriptedAI::AttackStart(who);
			}

            void EnterCombat(Unit* /*who*/)
            {
				me->CastSpell(me, SPELL_FROZEN_MALLET, true);

                events.ScheduleEvent(EVENT_FROZEN_ORB_STALKER, 12000);
                events.ScheduleEvent(EVENT_FREEZING_GROUND, 7000);
				if (pInstance)
					pInstance->SetData(EVENT_TORAVON, IN_PROGRESS);
            }

			void JustDied(Unit* )
			{
				if (pInstance)
				{
					pInstance->SetData(EVENT_TORAVON, DONE);
					pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_WHITEOUT);
				}
			}

			void JustSummoned(Creature* cr)
			{
				summons.Summon(cr);
			}

            void UpdateAI(uint32 diff)
            {
                if (!UpdateVictim())
                    return;

                events.Update(diff);
                if (me->HasUnitState(UNIT_STATE_CASTING))
                    return;

                switch (events.GetEvent())
                {
					case EVENT_FREEZING_GROUND:
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
							me->CastSpell(target, SPELL_FREEZING_GROUND, false);
                        events.RepeatEvent(20000);
                        break;
                    case EVENT_FROZEN_ORB_STALKER:
                        me->CastCustomSpell(SPELL_FROZEN_ORB, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 3), me, false);
                        events.RepeatEvent(35000);
						events.ScheduleEvent(EVENT_CHECK_SUMMONS, 10000);
                        break;
					case EVENT_CHECK_SUMMONS:
						for (SummonList::iterator i = summons.begin(); i != summons.end();)
						{
							if (Creature* cr = ObjectAccessor::GetCreature(*me, *i))
							{
								if (!cr->IsAlive())
									summons.erase(i++);
								else
									++i;
							}
							else
								summons.erase(i++);
						}
						if (summons.empty())
						{
							events.PopEvent();
							me->CastSpell(me, SPELL_WHITEOUT, false);
							break;
						}
						events.RepeatEvent(2000);
						break;
                }

                DoMeleeAttackIfReady();
            }
        };

        CreatureAI* GetAI(Creature* creature) const
        {
            return new boss_toravonAI(creature);
        }
};

class npc_frozen_orb : public CreatureScript
{
public:
    npc_frozen_orb() : CreatureScript("npc_frozen_orb") { }

    struct npc_frozen_orbAI : public ScriptedAI
    {
        npc_frozen_orbAI(Creature* creature) : ScriptedAI(creature)
        {
        }

		uint32 switchTimer;

        void Reset()
        {
			switchTimer = 9000;
			me->CastSpell(me, SPELL_FROZEN_ORB_AURA, true);
			me->CastSpell(me, SPELL_FROZEN_ORB_DMG, true);
        }

        void EnterCombat(Unit* /*who*/)
        {
            me->SetInCombatWithZone();
        }

        void UpdateAI(uint32 diff)
        {
			switchTimer += diff;
			if (switchTimer >= 10000)
			{
				switchTimer = 0;
				me->getThreatManager().resetAllAggro();
				if (Player* player = SelectTargetFromPlayerList(100.0f))
					me->AddThreat(player, 100000.0f);
			}
        }
    };

    CreatureAI* GetAI(Creature* creature) const
    {
        return new npc_frozen_orbAI(creature);
    }
};

class npc_frozen_orb_stalker : public CreatureScript
{
public:
    npc_frozen_orb_stalker() : CreatureScript("npc_frozen_orb_stalker") { }

    struct npc_frozen_orb_stalkerAI : public NullCreatureAI
    {
        npc_frozen_orb_stalkerAI(Creature* creature) : NullCreatureAI(creature)
        {
		}

		void Reset()
		{
			me->CastSpell(me, SPELL_FROZEN_ORB_STALKER_VISUAL, true);
		}

		void JustSummoned(Creature* cr)
		{
			if (InstanceScript* pInstance = me->GetInstanceScript())
				if (Creature* toravon = ObjectAccessor::GetCreature(*me, pInstance->GetData64(EVENT_TORAVON)))
					if (toravon->AI())
						toravon->AI()->JustSummoned(cr);
		}
    };

    CreatureAI* GetAI(Creature* creature) const
    {
        return new npc_frozen_orb_stalkerAI(creature);
    }
};


void AddSC_boss_toravon()
{
    new boss_toravon();
    new npc_frozen_orb();
	new npc_frozen_orb_stalker();
}
